import bpy
from typing import List
from ...addon.naming import FluidLabNaming
from .common_list_methods import FLUIDLAB_CommonList
from bpy.types import PropertyGroup, UIList, Object, Collection
from ...libs.functions.collections import remove_collection_if_is_empty
from ...libs.functions.basics import set_active_object, rm_ob
from ...libs.functions.get_common_vars import get_common_vars
from ...libs.functions.particles import particle_system_remove
# from ....libs.functions.collections import remove_collection
from .active_mesh_props.props_switchers import ActiveMeshItemSwitchesProps
from bpy.props import StringProperty, IntProperty, CollectionProperty, IntProperty, BoolProperty, PointerProperty
from .updaters.props_update_particles import ui_update

from .active_emitter_props.props_emission import ActiveEmitterEmissionProps
from .active_emitter_props.props_physics import ActiveEmitterPhysicsProps
from .active_emitter_props.props_springs import ActiveEmitterSpringsProps

from .active_emitter_props.anim.props_weights_anim import ActiveGroupWeightsAnimProps
from .active_emitter_props.anim.props_geometry_emitter_anim import ActiveEmitterGeometryEmitterAnimProps


""" Fluids Emitters List """

        
class FLUIDLAB_UL_draw_fluids_emitters(UIList):

    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
        
        # Si por lo que sea no tiene id_name:
        if not item.id_name:
            layout.prop(item, "remove", text="Clear", icon='X')
            return
        
        if not item.group_coll:
            layout.prop(item, "remove", text="Clear", icon='X')
            return

        # Si el usuario a borrado el bojeto emitter:
        emitter_ob = next((ob for ob in item.group_coll.objects if ob.fluidlab.id_name == "Emitter_"+ item.id_name), None)
        if not emitter_ob:
            layout.prop(item, "remove", text="Clear", icon='X')
            return
        
        main_modules = context.scene.fluidlab.ui.main_modules
        wm = context.window_manager

        left_sect = layout.row(align=True)

        # Cuando etoy en modo popup (el Fluid interactions popup), muestro los cehckbox de interactive:
        if context.region.type == 'WINDOW':
            
            if FluidLabNaming.WM_BAKE_POPUP_OPENED in wm:
                
                # CUANDO SON POPUPS DE BAKE:
                left_sect.separator()
                left_sect.prop(item, "bakeme", text="")
            
            else:

                # --- El resto de popups --- #

                if main_modules == 'FLUID_INTERACTIONS':
                    left_sect.separator()
                    left_sect.prop(item, "interactive", text="")
                
                # Cuando etoy en modo popup, (el Add Mesh popup), muestro los cehckbox de meshme:
                if main_modules == 'MESH':
                    left_sect.separator()
                    left_sect.prop(item, "meshme", text="")

        # Cuando estoy y no estoy en popups:
        # left_sect.prop(item, "label_txt", text="", emboss=False)

        emitter_ob = next((ob for ob in item.group_coll.objects if ob.fluidlab.id_name == "Emitter_"+ item.id_name ), None)
        if emitter_ob:
            left_sect.prop(emitter_ob, "name", text="", emboss=False)

        # Cuando NO etoy en modo popup:
        if context.region.type == 'UI':
            # Right Section:
            right_sect = left_sect.row(align=True)
            right_sect.alignment = 'RIGHT'

            # Visible icon:
            right_sect.prop(item, "visible", text="", icon='HIDE_OFF' if item.visible else 'HIDE_ON', emboss=False)

            # Show Emitter:
            right_sect.prop(item, "show_emitter_vp", text="", icon='MESH_CUBE' if item.show_emitter_vp else 'LIGHTPROBE_SPHERE', emboss=False)

            # Enable icon:
            right_sect.prop(item, "enable", text="", icon='RESTRICT_VIEW_OFF' if item.enable else 'RESTRICT_VIEW_ON', emboss=False)

            # Remove icon:
            rm_button = right_sect.row(align=True)
            rm_button.alert = True
            rm_button.prop(item, "remove", text="", emboss=False, icon='X')


class FluidEmittersListItem(PropertyGroup):
    label_txt: StringProperty(name="Name")
    id_name: StringProperty(name="ID")

    group_coll: PointerProperty(type=Collection) 
    vertex_ob: PointerProperty(type=Object)
    vertex_ob_dead: PointerProperty(type=Object)

    # para el popup de mesh (remesh):
    meshme: BoolProperty(default=True)

    #---------------------------------------------------------------------------------
    # Propiedades guardadas en el active_emitter_item.emission.x:
    #---------------------------------------------------------------------------------
    emission: PointerProperty(type=ActiveEmitterEmissionProps)
    #---------------------------------------------------------------------------------
    # Propiedades guardadas en el active_emitter_item.physics.x: (incluidas las Anim)
    #---------------------------------------------------------------------------------
    physics: PointerProperty(type=ActiveEmitterPhysicsProps)
    #---------------------------------------------------------------------------------
    # Propiedades guardadas en el active_emitter_item.springs.x: (incluidas las Anim)
    #---------------------------------------------------------------------------------
    springs: PointerProperty(type=ActiveEmitterSpringsProps)
    #---------------------------------------------------------------------------------
    # Anim weights_props:
    weights: PointerProperty(type=ActiveGroupWeightsAnimProps)
    #---------------------------------------------------------------------------------
    # Anim Geometry Emitter Switcher:
    geometry_emitter: PointerProperty(type=ActiveEmitterGeometryEmitterAnimProps)
    #---------------------------------------------------------------------------------

        
    def do_remove(self, context):
        fluid_groups = get_common_vars(context, get_fluid_groups=True)
        group = fluid_groups.get_item_from_group_coll(self.group_coll)
        
        if not group:
            return

        previous_selection = context.selected_objects
        previous_active = context.active_object

        emitters_list = group.emitters

        emitter_ob = next((ob for ob in self.group_coll.objects if ob.fluidlab.id_name == "Emitter_"+ self.id_name ), None)
        if emitter_ob:

            # Eliminamos sus particulas:
            particle_system_remove(context, emitter_ob, FluidLabNaming.PS_NAME, FluidLabNaming.PS_NAME, 'START_WITH')

            # Lo sacamos de su collection:
            if emitter_ob.name in group.group_coll.objects: 
                group.group_coll.objects.unlink(emitter_ob)
            
            if len(emitter_ob.users_collection) <= 0:
                context.scene.collection.objects.link(emitter_ob)
            
        # Eliminamos el vertext ob alive:
        rm_ob(context, self.vertex_ob)

        # Eliminamos el vertext ob dead:
        rm_ob(context, self.vertex_ob_dead)

        remove_collection_if_is_empty(context, group.vertex_coll)
        remove_collection_if_is_empty(context, FluidLabNaming.VERTEX_COLL)

        # remove_collection_if_is_empty(context, active_group.group_coll)
        
        # Lo eliminamos del listado:
        emitters_list.remove_item(self.id_name)
        emitters_list.list_index = emitters_list.length-1 if not emitters_list.is_void else 0

        # Si está vacio el listado emitters eliminamos el grupo:
        # if emitters_list.is_void:
        #     active_group.remove = True

        if previous_active:
            set_active_object(context, previous_active)

        if previous_selection:
            bpy.ops.object.select_all(action='DESELECT')
            for ob in previous_selection:
                ob.select_set(True)
        

    remove: BoolProperty(
        default=False, 
        update=do_remove
    )

    def visible_update(self, context):
        emitter_ob = next((ob for ob in self.group_coll.objects if ob.fluidlab.id_name == "Emitter_"+ self.id_name ), None)
        if emitter_ob:
            emitter_ob.hide_set(not self.visible)

    visible: BoolProperty(
        default=True,
        update=visible_update
    )

    def show_emitter_vp_update(self, context):
        emitter_ob = next((ob for ob in self.group_coll.objects if ob.fluidlab.id_name == "Emitter_"+ self.id_name ), None)
        if emitter_ob:
            emitter_ob.show_instancer_for_viewport = self.show_emitter_vp

    show_emitter_vp: BoolProperty(default=False, update=show_emitter_vp_update)


    def enable_update(self, context):
        emitter_ob = next((ob for ob in self.group_coll.objects if ob.fluidlab.id_name == "Emitter_"+ self.id_name ), None)
        if emitter_ob:
            mod = next((mod for mod in emitter_ob.modifiers if mod.type == 'PARTICLE_SYSTEM' and mod.name.startswith(FluidLabNaming.PS_NAME)), None)
            if mod:
                mod.show_viewport = self.enable

    enable: BoolProperty(
        default=True, 
        update=enable_update
    )

    # Subsections switchers ( iconos de la cadenita para Global/Local ):
    #-------------------------------------------------------------------
    switchers: PointerProperty(type=ActiveMeshItemSwitchesProps)

    # Control de Popups:
    #-------------------

    # Para cuando muestro el popup de Fluid interactions:
    interactive: BoolProperty(
        default=True
    )

    # Para el popup de bake:
    bakeme: BoolProperty(default=False)

    # Para cambiar entre grid resolution o el size:
    def gr_sz_toggle_update(self, context):

        fluid_groups = get_common_vars(context, get_fluid_groups=True)
        active_group = fluid_groups.active
        emitters_list = active_group.emitters
        active_emitter_item = emitters_list.active
        
        if self.gr_sz_toggle:
            active_emitter_item.emission.size = active_emitter_item.emission.size
        else:
            active_emitter_item.emission.grid_resolution = active_emitter_item.emission.grid_resolution

    gr_sz_toggle: BoolProperty(name="Size Particles", description="Adjust the siez manually", default=False, update=gr_sz_toggle_update)


class FluidEmittersList(PropertyGroup, FLUIDLAB_CommonList):

    def list_index_update(self, context):

        item = self.active
        if not item:
            return
        
        # Hago activo el emitter activo, para comprobar en la ui de blender sus valores visualmente:
        active_emitter_item = item
        active_emitter = self.get_current_emitter

        # Si el usuario borró el emitter:
        if not active_emitter:
            return

        set_active_object(context, active_emitter)

        ui_update(context, active_emitter_item, without_self_ob=False)

        bpy.ops.object.select_all(action='DESELECT')
        active_emitter.select_set(True)
    
    list_index: IntProperty(name="Layer List", description="The Layer List", default=-1, update=list_index_update)
    list: CollectionProperty(type=FluidEmittersListItem)
    

    # Fluid Emitters List Methods:
    def add_item(self, item_id:str, label_txt:str, group_coll:Collection, ob: Object, vertex_ob: Object, vertex_ob_dead: Object, switches_status:List[tuple]=None) -> FluidEmittersListItem:

        item = self.list.add()
        item.id_name = item_id
        item.label_txt = label_txt
        item.group_coll = group_coll

        # guardamos los vertex ob alive y vertex ob dead: 
        item.vertex_ob = vertex_ob
        item.vertex_ob_dead = vertex_ob_dead

        # los relacionamos con el item_id:
        ob.fluidlab.id_name = "Emitter_" + item_id
        vertex_ob.fluidlab.id_name = "Vertex_" + item_id
        vertex_ob_dead.fluidlab.id_name = "Vertex_dead_" + item_id

        # Para que al duplicar grupos se mantengan los estados de los switchers, y no se igualen todos a globales:
        if switches_status:
            
            for switch_tuple in switches_status:
                switch_prop, mode = switch_tuple

                # Solo si esta en modo local lo seteamos. 
                # Ya que por default son globales:
                if mode: # <- Si es True es Global.
                    continue

                setattr(item.switchers, switch_prop, mode)
        
        # Set the last item active:
        self.list_index = self.length-1

        return item
        
    
    @property
    def get_current_emitter(self):
        emitter_ob = next((ob for ob in self.list[self.list_index].group_coll.objects if ob.fluidlab.id_name == "Emitter_"+ self.list[self.list_index].id_name ), None)
        return emitter_ob
        
    @property
    def get_all_emitters(self):
        return [ob for item in self.list if item.group_coll is not None for ob in item.group_coll.objects if ob.fluidlab.id_name == "Emitter_"+ item.id_name]

    @property
    def get_all_bakeable_emitters(self):
        return [ob for item in self.list if item.group_coll is not None and item.bakeme for ob in item.group_coll.objects if ob.fluidlab.id_name == "Emitter_"+ item.id_name]

    @property
    def get_all_p_settings(self):
        emitters = self.get_all_emitters
        return [emitter_ob.particle_systems.active.settings for emitter_ob in emitters if emitter_ob.particle_systems.active]
